package br.com.tcc.automacao.util;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import br.com.tcc.automacao.permissao.negocio.Permissao;
import br.com.tcc.automacao.usuario.negocio.Usuario;

public class HibernateUtil {
    
    static Logger logger = Logger.getLogger(HibernateUtil.class);
    
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private static Configuration configuration = new Configuration();
    private static org.hibernate.SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;
    
    private HibernateUtil() {
    }
    
    /**
     * Returns the ThreadLocal Session instance.  Lazy initialize
     * the <code>SessionFactory</code> if needed.
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
	Session session = (Session) threadLocal.get();
	
	if (session == null || !session.isOpen()) {
	    if (sessionFactory == null) {
		rebuildSessionFactory();
	    }
	    session = (sessionFactory != null) ? sessionFactory.openSession()
		    : null;
	    threadLocal.set(session);
	}
	return session;
    }
    
    /**
     *  Rebuild hibernate session factory
     */
    public static void rebuildSessionFactory() {
	try {
	    
	    configuration.configure(configFile);
	    sessionFactory = configuration.buildSessionFactory();
	} catch (Exception e) {
	    
	    e.printStackTrace();
	}
    }
    
    /**
     *  Close the single hibernate session instance.
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
	Session session = (Session) threadLocal.get();
	threadLocal.set(null);
	
	if (session != null) {
	    session.close();
	}
    }
    
    /**
     *  return session factory
     */
    public static org.hibernate.SessionFactory getSessionFactory() {
	return sessionFactory;
    }
    
    /**
     *  return session factory
     *	session factory will be rebuilded in the next call
     */
    public static void setConfigFile(String configFile) {
	HibernateUtil.configFile = configFile;
	sessionFactory = null;
    }
    
    /**
     *  return hibernate configuration
     */
    public static Configuration getConfiguration() {
	return configuration;
    }
    
    public static Object incluir(Object o){
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    sessao.save(o);
	    transaction.commit();
	    sessao.flush();
	} catch (Exception e) {
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    logger.error("Erro ao incluir objeto do tipo "+o.getClass(), e);
	    e.printStackTrace();
	    return null;
	}finally{
	    closeSession();
	}
	return o;
    }
    
    public static String incluirUsuario(Usuario usuario ){
		Usuario u = null;
		try {
			Session session = getSession();
			final Transaction trans = session.beginTransaction();
			List<Permissao> permissoes = new ArrayList<Permissao>();
			DetachedCriteria dc = DetachedCriteria.forClass(Usuario.class);
			
			dc.add(Restrictions.eq("login", usuario.getLogin()));
			
			u = (Usuario) consultarUsuarioUnico(dc);
			if(u == null){
				u = usuario;

				if(usuario.getPermissoes() != null){
					for(Permissao p : usuario.getPermissoes()){
						Permissao per = consultarPermissao(p, session);
						if(!jaExiste(per, session) &&  p.getPermissaoEnum() != null){
							Permissao pe = new Permissao();
							pe.setPermissaoEnum(p.getPermissaoEnum());
							session.persist(pe);
							permissoes.add(pe);
						}else{
							if( p.getPermissaoEnum() != null){
								permissoes.add(per);
							}
						}
					}
				}

			}else{
				return "existe";
			}


			u.setPermissoes(permissoes);
			session.merge(u);
			trans.commit();

			return "sucesso";
		} catch (Exception e) {
			sessionFactory.getCurrentSession().beginTransaction().rollback();
			logger.error("Erro ao incluir objeto do tipo "+usuario.getClass(), e);
			e.printStackTrace();
			return "falha";
		}finally{
			  closeSession();
		}
		
	}
    
    public static String atualizarUsuario(Usuario usuario ){
		Usuario u = null;
		try {
			Session session = getSession();
			final Transaction trans = session.beginTransaction();
			List<Permissao> permissoes = new ArrayList<Permissao>();
			DetachedCriteria dc = DetachedCriteria.forClass(Usuario.class);
			
			dc.add(Restrictions.eq("login", usuario.getLogin()));
			
			u = (Usuario) consultarUsuarioUnico(dc);
			if(u != null){
				if(usuario.getPermissoes() != null){
					for(Permissao p : usuario.getPermissoes()){
						Permissao per = consultarPermissao(p, session);
						if(!jaExiste(per, session) &&  p.getPermissaoEnum() != null){
							Permissao pe = new Permissao();
							pe.setPermissaoEnum(p.getPermissaoEnum());
							session.persist(pe);
							permissoes.add(pe);
						}else{
							if( p.getPermissaoEnum() != null){
								permissoes.add(per);
							}
						}
					}
				}

			}
			
			u.setNome(usuario.getNome());
			u.setSenha(usuario.getSenha());
			u.setPermissoes(permissoes);
			session.merge(u);
			trans.commit();

			return "sucesso";
		} catch (Exception e) {
			sessionFactory.getCurrentSession().beginTransaction().rollback();
			logger.error("Erro ao incluir objeto do tipo "+usuario.getClass(), e);
			e.printStackTrace();
			return "falha";
		}finally{
			  closeSession();
		}
		
	}
    
    public static Boolean jaExiste(Permissao permissao, Session sessao){

		if(permissao != null){
			Permissao p = consultarPermissao(permissao, sessao);
			if(p != null){
				return true;
			}
		}
		return false;
	}
    
    public static Permissao consultarPermissao(Permissao permissao, Session sessao){
		Permissao p = null;
		List<Permissao> permissoes = null;

		DetachedCriteria dc = DetachedCriteria.forClass(Permissao.class);

		dc.add(Restrictions.eq("permissaoEnum",  permissao.getPermissaoEnum()));

		permissoes = dc.getExecutableCriteria(sessao).list();

		if(permissoes.size() > 0){
			for(Permissao perm: permissoes){
				if(perm.getPermissaoEnum() == permissao.getPermissaoEnum()){
					p = perm;
				}
			}
		}

		return p;
	}
    
    
    public static void atualizar(Object o) {
	
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    sessao.merge(o);
	    transaction.commit();
	    sessao.flush();
	} catch (Exception e) {			
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    logger.error("Erro no metodo atualizar", e);
	}finally{
	    closeSession();
	}
	
    }
    
    public static void remover(Object o){
	
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    sessao.delete(o);
	    transaction.commit();
	    sessao.flush();
	} catch (Exception e) {			
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    logger.error("Erro no metodo remover", e);
	}finally{
	    closeSession();
	}
	
    }
    
    public static Object consultar(Class objClass, long id){
	Object objGet = null;
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    objGet = sessao.get(objClass, id);
	} catch (HibernateException e) { 
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    System.err.println(e.fillInStackTrace());
	    e.printStackTrace();
	}finally{
	    closeSession();
	}
	return objGet;
    }
    
    public static Object consultar(DetachedCriteria dc){
	Object objGet = null;
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    objGet = dc.getExecutableCriteria(sessao);
	} catch (HibernateException e) { 
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    System.err.println(e.fillInStackTrace());
	}finally{
	    closeSession();
	}
	return objGet;
    }
    public static Object consultarUnicoResult(DetachedCriteria dc){
	Object objGet = null;
	List<Object> list = null;
	try {
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    list = dc.getExecutableCriteria(sessao).list();
	} catch (HibernateException e) { 
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    System.err.println(e.fillInStackTrace());
	}finally{
	   closeSession();
	}
	
	if(list != null && !list.isEmpty()){
	    objGet = list.get(0);
	}
	
	return objGet;
    }
    public static Object consultarUsuarioUnico(DetachedCriteria dc){
    	Object objGet = null;
    	List<Object> list = null;
    	try {
    		Session sessao = getSession();
    		//final Transaction transaction = sessao.beginTransaction();
    		list = dc.getExecutableCriteria(sessao).list();
    	} catch (HibernateException e) { 
    		sessionFactory.getCurrentSession().beginTransaction().rollback();
    		System.err.println(e.fillInStackTrace());
    	}
    	
    	if(list != null && !list.isEmpty()){
    		objGet = list.get(0);
    	}
    	
    	return objGet;
    }
    
    public static List listar(DetachedCriteria dc) {
	List list = null;
	try{
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    list = dc.getExecutableCriteria(sessao).list();
	} catch (HibernateException e) { 
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    System.err.println(e.fillInStackTrace());
	}finally{
	    closeSession();
	}
	
	return list;
	
    }
    
    public static List listarSQL(String sql, Class clazz) {
	List list = null;
	try{
	    
	    
	    Session sessao = getSession();
	    final Transaction transaction = sessao.beginTransaction();
	    Query query = sessao.createSQLQuery(sql).addEntity(clazz);
	    list= query.list();
	} catch (HibernateException e) { 
	    sessionFactory.getCurrentSession().beginTransaction().rollback();
	    System.err.println(e.fillInStackTrace());
	}finally{
	    closeSession();
	}
	
	return list;
	
    }
    
    
    
}



